<?php
//http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=%D1%81%D0%B5%D1%82%D1%8C%20%D0%A2%D0%B0%D0%B2%D1%80%D0%B8%D1%8F%20%D0%92
//https://maps.googleapis.com/maps/api/place/search/json?location=50.430145,30.460953&name=Амстор&sensor=false&key=AIzaSyCPLPHveBm1g-6Be3MlMWpNtBIB2eORwf4&rankby=distance
//https://maps.googleapis.com/maps/api/place/search/json?location=50.430145,30.460953&name=Амстор&sensor=false&key=AIzaSyCPLPHveBm1g-6Be3MlMWpNtBIB2eORwf4&rankby=distance

include_once $_SERVER['DOCUMENT_ROOT'].'/lib/Cache.php';

class Google{
	private $key='AIzaSyCPLPHveBm1g-6Be3MlMWpNtBIB2eORwf4';
	private $lang='ru';
	private $supportedLangs=array( 'ru','uk','ro','en' );
	public	$curJson=false;

	protected static $_instance;
	private function __construct(){}
	private function __clone(){}
	public static function inst(){
	  if( null===self::$_instance ){
	    self::$_instance=new self();
		}
		return self::$_instance;
	}
	
	protected $errors=array('err'=>array(),'wrn'=>array());
	protected function error($msg){ $this->errors['err'][]=$msg; return false;}
	protected function warning($msg){ $this->errors['wrn'][]=$msg; return false;}
	public function getError(){ return $this->errors['err'][ count($this->errors['err'])-1 ]; }
	public function getErrors(){ return $this->errors['err']; }
	public function getWarning(){ return $this->errors['wrn'][ count($this->errors['wrn'])-1 ]; }
	public function getWarnings(){ return $this->errors['wrn']; }


	function setLang($ln){
	  if( !in_array($ln, $this->supportedLangs) ) return false;
//echo ' seted:',$ln;
	  $this->lang=$ln;
	  return true;
	}
	
	/**************************
	 *	Произвольный запрос к API
	***************************/
	function request($query,$headers=array()){
	  
	  //Запрашиваю
		$baseUrl='https://maps.googleapis.com';
		//$baseUrl='http://maps.googleapis.com';
		
		// Create a stream
		// File_get_content with headers http://stackoverflow.com/questions/2107759/php-file-get-contents-and-headers
		$context = stream_context_create(
			array(
			  'http'=>array(
			    'method'=>"GET",
			    'header'=> implode("\r\n",$headers) //"Accept-language: en\r\n"
			  )
			)
		);

	  $json=@file_get_contents($baseUrl.$query, false, $context);

	  if(empty($json)) return $this->error('Empty google response');
		
	  $dt=json_decode($json);
	  $this->curJson=$json;
		//echo $baseUrl.$query.'<br />'.$json; exit();
		return $dt;
	}
	
	/**
   * Makes request to google maps API to make geocode;
   * @name geocode
   * @author  John Bor <johncomua@gmail.com>
   * @param array @reg  array(addr(or lat,lng,radius),query, lang, country, region, city)
   */
	function geocode($req){
	  if( is_string($req) ) $req=array('addr'=>$req);
	  
	  if(empty($req['addr']) && (empty($req['lat']) ||  empty($req['lng'])) ){
			return $this->error('Не переданы параметры геокодинга Google');
		}

	  if( !empty( $req['lang'] ) ) $this->setLang($req['lang']);
	  
		if(!empty($req['addr'])){
			if(strpos($req['addr'], '/')!==false) $req['addr']=substr($req['addr'], 0, strpos($req['addr'], '/'));
			$req['addr']=trim($req['addr']);
			$req['addr']=strtr($req['addr'], array("'"=>'','"'=>'','`'=>''));
			$req['addr']=urlencode($req['addr']);
			
			$query='/maps/api/geocode/json?address='.$req['addr'].'&language='.$this->lang;

		  $components=array();
		  if(!empty($req['country']))	$components[]='country:'.urlencode($req['country']);
		  if(!empty($req['region']))	$components[]='administrative_area:'.urlencode($req['country']);
		  if(!empty($req['city']))		$components[]='locality:'.urlencode($req['country']);

	    if(!empty($components)) $query.='&components='.implode('|',$components);

		}else{
		  $query='/maps/api/geocode/json?latlng='.$req['lat'].','.$req['lng'].'&language='.$this->lang;
		}
		
		//Извлекаю из кеша
		if($tst=Cache::inst()->get($query) ){
	     return $tst;
		}

    $googleInfo=$this->request($query);

		if( empty($googleInfo->results) ){
		  //echo 'empty<br />'.$query.'<pre class="debug">'.print_r ( $googleInfo ,true).'</pre>';exit();
	    return $this->error('empty Google geocode response');
		}
		
		/*
		$req['filter']=array(
		  0=>'street_number,location'
		)
		*/
		$results=array();
		if(!empty($req['filter'])){
		  for( $r=0, $rcnt=count($googleInfo->results); $r<$rcnt; $r++ ){
		    $match=true;
			  for( $f=0, $fcnt=count($req['filter']); $f<$fcnt; $f++  ){
			    for( $i=0, $cnt=count($googleInfo->results[$r]->address_components[$f]->types); $i<$cnt; $i++ ){
			      if( strpos($req['filter'][$f],$googleInfo->results[$r]->address_components[$f]->types[$i])===false ){
			        $match=false;
			        break 2;
						}
					}
				}
				if($match) $results[]=$googleInfo->results[$r];
		  }
		  //echo 'FILTERED:<pre class="debug">'.print_r ( $results ,true).'</pre>';exit();
		  $googleInfo->results=$results;
		  unset($results, $match, $rcnt,$fcnt,$cnt, $f,$f,$i);
		}
		
		$geoDetail=$this->parsegeoDetails($googleInfo->results[0]);
		
   //кеширую
	  if( !Cache::inst()->set( $query, $geoDetail ) ){
	    //echo '<pre class="debug">'.print_r ( Cache::inst()->getErrors() ,true).'</pre>';
	    $this->error('ошибка кеширования - не удалось сохранить данные','wrn');
		}
		
		return $geoDetail;
	}
	
	function parseGeoDetails($result){
		//Формализую результат
		$geoDetail=array(
		  'countryIso'=>false,
		  'country'=>false,
		  'region'=>false,
		  'city'=>false,
		  'urbanarea'=>false,
		  'street'=>false,
		  'number'=>false,
		  'lat'=>false,
		  'lng'=>false,
		  'formatedAddr'=>false,
		  'geometry'=>false,
		);
		$geoDetail['lat']=$result->geometry->location->lat;
		$geoDetail['lng']=$result->geometry->location->lng;
		$geoDetail['formatedAddr']=$result->formatted_address;
		$geoDetail['geometry']=json_encode($result->geometry);

		for( $i=0, $cnt=count($result->address_components); $i<$cnt; $i++ ){
			  switch( $result->address_components[$i]->types[0] ){
			    case 'country':
			      $geoDetail['country']=$result->address_components[$i]->long_name;
			      $geoDetail['countryIso']=$result->address_components[$i]->short_name;
						break;
			    case 'administrative_area_level_1':
			    	$geoDetail['region']=$result->address_components[$i]->long_name;
						break;
			    case 'locality':
			      $geoDetail['city']=$result->address_components[$i]->long_name;
						break;
			    case 'sublocality':
			    case 'sublocality_level_1':
			      $geoDetail['urbanarea']=$result->address_components[$i]->long_name;
						break;
					case 'route':
					  $geoDetail['street']=$result->address_components[$i]->long_name;
					  break;
					case 'street_number':
					  $geoDetail['number']=$result->address_components[$i]->long_name;
					  break;
				}
		}
		if(empty($geoDetail['urbanarea']))$geoDetail['urbanarea']=$geoDetail['city'];
		if(empty($geoDetail['region']))$geoDetail['region']=$geoDetail['country'];
	  return $geoDetail;
	}
	
	
	/**
   * Makes request to google places API to find place near lat lng find(array(lat=>'',lng=>'',query=>'',radius=>''));
   * @name find
   * @author  John Bor <johncomua@gmail.com>
   * @param array @reg  array(lat,lng,query,radius)
   */
	function find($req){
	  if(empty($req['query']) || empty($req['lat']) ||  empty($req['lng']) ){
     	return $this->error('Не переданы параметры поиска в Google адресах','wrn');
		}

		if(strpos($req['query'], '/')!==false){
		  $req['query']=substr($req['query'], 0, strpos($req['query'], '/'));
		}
		$req['query']=trim($req['query']);
		$req['query']=strtr($req['query'], array("'"=>'','"'=>'','`'=>''));
		$req['query']=urlencode($req['query']);

		if( !empty( $req['lang'] ) ) $this->setLang($req['lang']);

	  //Запрос поиска Места
	  $query='/maps/api/place/search/json?location='.$req['lat'].','.$req['lng'].'&name='.$req['query'].'&sensor=false&lang='.$this->lang.'&key='.$this->key;

		if(!empty($req['radius'])) $req['radius']=intval($req['radius']);
		if(!empty($req['radius'])) $query.='&radius='.$req['radius'];
		else $query.='&rankby=distance';

//echo '<br />'.$query.'<br />';

    //Есть ли в кеше?
		if(!$dt=Cache::inst()->get($query) ){
		  $dt=$this->request($query,array('Accept-language: '.$this->lang ));
		  
			//Validate response
		  if( empty($dt->results) ){
		    return $this->error('Place not found');
			}
			
	   	//кеширую
		  if( !Cache::inst()->set( $query, $dt, CACHE::day ) ){
		    $this->warning('ошибка кеширования - не удалось сохранить результаты поиска места данные');
			}
		}
//echo '<pre class="debug">'.print_r ( $dt ,true).'</pre>';exit();

		//Запрос на детали места
		$ref_id=$dt->results[0]->reference;
		$query='/maps/api/place/details/json?reference='.$ref_id.'&sensor=false&lang='.$this->lang.'&key='.$this->key;
		
		if( $item=Cache::inst()->get($query) ) return $item;
	  $item=$this->request($query,array('Accept-language: '.$this->lang ));
		if(empty( $item->result )){
	    return $this->error('Детали о месте не найдены');
		}
		$result=$this->parsegeoDetails($item->result);
		$result['name']=$item->result->name;
		$result['formatted_address']=$item->result->formatted_address;
    $result['url']=((!empty($item->result->url)))?$item->result->url:'';
    $result['dataProvider']='GM';
    $result['wideInfo']=$item->result;

    //кеширую
	  if( !Cache::inst()->set( $query, $result, CACHE::day ) ){
	    $this->warning('ошибка кеширования - не удалось сохранить результаты поиска места данные');
		}
		
	  return $result;
	}
}
?>